#include "Globals.h"

//#include "stdafx.h"

#include "API/TES/TESDataHandler.h"
#include "API/Settings/Settings.h"
#include "API/Settings/SettingCollection.h"

#include <boost/static_assert.hpp>
#include "Utilities.h"

#include "API/Magic/EffectSetting.h"
#include "API/Actors/ActorValues.h"
#include "API/Items/TESObjectCLOT.h"

#ifdef OBLIVION
#include <ctime>
boost::mt19937 RNG::mt(time(0));

boost::uniform_real<double> pctRng(0, 100);
boost::variate_generator<boost::mt19937&, boost::uniform_real<double> > RNG::pctGen(mt, pctRng);

boost::uniform_int<UInt8> flipRng(0, 1);
boost::variate_generator<boost::mt19937&, boost::uniform_int<UInt8> > RNG::flipGen(mt, flipRng);
bool RNG::flipFn() { return flipGen() != 0; }
#endif

Souls* kSouls = NULL;
obseIntfcFunctor callScptNoArgs (NULL);
obseIntfcFunctor getSoulLvFromLL (NULL);
obseIntfcFunctor addFormToSavegame (NULL);

EffectSetting* FOMF = NULL;
EffectSetting* DRMF = NULL;
Setting* fAutoEnchantmentRateBase = NULL;
Setting* fAutoEnchantmentRateMult = NULL;
TESObjectCLOT* token = NULL;

double obseIntfcFunctor::operator()(UInt32 val) {
	if ( function )
		return (*function)(val);
	else
		_ERROR("obseIntfcFunctor &lt;%p&gt; has null function.", this);
	return 0;
}

obseIntfcFunctor::obseIntfcFunctor(obseFunction* func)
	: function(func)
{
	//_VMESSAGE("obseIntfcFunctor &lt;%p&gt; created with function &lt;%p&gt;.", this, func);
}

UInt32 Souls::kSoulgemIDs_Array[] =
{
	0x00000000, // (none for Subpetty)
	0x00023D67, // SoulGemEmpty1Petty
	0x00023D69, // SoulGemEmpty2Lesser
	0x00015B8B, // SoulGemEmpty3Common
	0x00015B8C, // SoulGemEmpty4Greater
	0x00015B8E, // SoulGemEmpty5Grand
	0x00000000, // (none for Ultra)
	0x00000000, // (none for Negative)
};

void Souls::Initialize() {
	_VMESSAGE("Initializing MagicFind.");
	if ( !FOMF ) {
		EffectSettingCollection::Add( Swap32('FOMF')
									, "FOMF"
									, Magic::kSchool_Mysticism
									, 10.0
									, 0
									, EffectSetting::kMgefFlag_MagnitudeIsPercent
									| EffectSetting::kMgefFlag_OnSelf
									| EffectSetting::kMgefFlag_OnTarget
									| EffectSetting::kMgefFlag_OnTouch
									| EffectSetting::kMgefFlag_NoArea
									| EffectSetting::kMgefFlag_Enchantments
									, ActorValues::kActorVal__UBOUND
									, 0);
		FOMF = EffectSetting::LookupByCode(Swap32('FOMF'));
		if ( FOMF ) {
			FOMF->SetFormID(0x777);
			FOMF->name = "Fortify Magic Find";
			FOMF->baseCost = 10.0;
			FOMF->barterFactor = 30;
			FOMF->enchantFactor = 0.4; // at default values, 20% constant effect enchantment from Grand soul
		}
	}
	
	if ( !DRMF ) {
		EffectSettingCollection::Add( Swap32('DRMF')
									, "DRMF"
									, Magic::kSchool_Mysticism
									, 10.0
									, 0
									, EffectSetting::kMgefFlag_Detrimental
									| EffectSetting::kMgefFlag_Hostile
									| EffectSetting::kMgefFlag_MagnitudeIsPercent
									| EffectSetting::kMgefFlag_OnSelf
									| EffectSetting::kMgefFlag_OnTarget
									| EffectSetting::kMgefFlag_OnTouch
									| EffectSetting::kMgefFlag_NoArea
									| EffectSetting::kMgefFlag_Enchantments
									| EffectSetting::kMgefFlag_UseActorValue
									, ActorValues::kActorVal__UBOUND
									, 0);
		DRMF = EffectSetting::LookupByCode(Swap32('DRMF'));
		if ( DRMF ) {
			DRMF->SetFormID(0x666);
			DRMF->name = "Drain Magic Find";
			DRMF->baseCost = 10.0;
			DRMF->barterFactor = 30;
			DRMF->enchantFactor = 0.4; // at default values, 20% constant effect enchantment from Grand soul
		}
	}

	if ( !token ) {
		TESForm* form = TESDataHandler::CreateForm(TESForm::kFormType_Clothing);
		if ( form ) {
			form->SetFormID(0x767);
			form->SetEditorID("DWaresToken");
			TESDataHandler::dataHandler->AddFormToHandler(form);
			token = (TESObjectCLOT*)form;
			token->name = "ARES Token";
			token->bipedModelFlags = TESBipedModelForm::kBipedModelFlag_NotPlayable;
			token->SetQuestItem(true);
		}
		else {
			_ERROR("Failed to create new TESObjectMISC for DWaresToken.");
		}
	}

	_VMESSAGE("Initializing souls.");
	// hack to prevent the GMSTs from having their FormIDs allocated.
	TESDataHandler* currHandler = TESDataHandler::dataHandler;
	TESDataHandler::dataHandler = NULL;

	if ( kSouls )
		delete kSouls;
	kSouls = new Souls;

	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fAutoEnchantmentRateBase", fAutoEnchantmentRateBase) )
		fAutoEnchantmentRateBase = new GameSetting("fAutoEnchantmentRateBase", 0.01f);

	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fAutoEnchantmentRateMult", fAutoEnchantmentRateMult) )
		fAutoEnchantmentRateMult = new GameSetting("fAutoEnchantmentRateMult", 0.02f);

	// undo hack.
	TESDataHandler::dataHandler = currHandler;
}

void Souls::Clear() {
	_VMESSAGE("Clearing souls.");
	if ( kSouls )
		delete kSouls;
	kSouls = NULL;

/*	MFUP = NULL;
	MFDN = NULL;*/
}

Souls::Souls() {	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideSubpetty", kSoulLvOvrGMSTs_Array[kSoulIndex_Subpetty]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Subpetty] = new GameSetting("iSoulLevelARESOverrideSubpetty", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverridePetty", kSoulLvOvrGMSTs_Array[kSoulIndex_Petty]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Petty] = new GameSetting("iSoulLevelARESOverridePetty", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideLesser", kSoulLvOvrGMSTs_Array[kSoulIndex_Lesser]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Lesser] = new GameSetting("iSoulLevelARESOverrideLesser", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideCommon", kSoulLvOvrGMSTs_Array[kSoulIndex_Common]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Common] = new GameSetting("iSoulLevelARESOverrideCommon", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideGreater", kSoulLvOvrGMSTs_Array[kSoulIndex_Greater]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Greater] = new GameSetting("iSoulLevelARESOverrideGreater", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideGrand", kSoulLvOvrGMSTs_Array[kSoulIndex_Grand]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Grand] = new GameSetting("iSoulLevelARESOverrideGrand", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideUltra", kSoulLvOvrGMSTs_Array[kSoulIndex_Ultra]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Ultra] = new GameSetting("iSoulLevelARESOverrideUltra", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelARESOverrideNegative", kSoulLvOvrGMSTs_Array[kSoulIndex_Negative]) )
		kSoulLvOvrGMSTs_Array[kSoulIndex_Negative] = new GameSetting("iSoulLevelARESOverrideNegative", (SInt32)0);

	
	kSoulLvOvrScpts_Array[kSoulIndex_Subpetty]	= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Petty]		= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Lesser]	= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Common]	= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Greater]	= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Grand]		= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Ultra]		= NULL;
	kSoulLvOvrScpts_Array[kSoulIndex_Negative]	= NULL;

	
	kSoulVlDefGMSTs_Array[kSoulIndex_Subpetty]	= NULL;
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValuePetty", kSoulVlDefGMSTs_Array[kSoulIndex_Petty]) )
		kSoulVlDefGMSTs_Array[kSoulIndex_Petty] = NULL;
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueLesser", kSoulVlDefGMSTs_Array[kSoulIndex_Lesser]) )
		kSoulVlDefGMSTs_Array[kSoulIndex_Lesser] = NULL;
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueCommon", kSoulVlDefGMSTs_Array[kSoulIndex_Common]) )
		kSoulVlDefGMSTs_Array[kSoulIndex_Common] = NULL;
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueGreater", kSoulVlDefGMSTs_Array[kSoulIndex_Greater]) )
		kSoulVlDefGMSTs_Array[kSoulIndex_Greater] = NULL;
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueGrand", kSoulVlDefGMSTs_Array[kSoulIndex_Grand]) )
		kSoulVlDefGMSTs_Array[kSoulIndex_Grand] = NULL;

	kSoulVlDefGMSTs_Array[kSoulIndex_Ultra]		= NULL;
	kSoulVlDefGMSTs_Array[kSoulIndex_Negative]	= NULL;


	kSoulLvDefFuncs_Array[kSoulIndex_Subpetty]	= &Souls::getDefLvSubpetty;
	kSoulLvDefFuncs_Array[kSoulIndex_Petty]		= NULL;
	kSoulLvDefFuncs_Array[kSoulIndex_Lesser]	= NULL;
	kSoulLvDefFuncs_Array[kSoulIndex_Common]	= NULL;
	kSoulLvDefFuncs_Array[kSoulIndex_Greater]	= NULL;
	kSoulLvDefFuncs_Array[kSoulIndex_Grand]		= NULL;
	kSoulLvDefFuncs_Array[kSoulIndex_Ultra]		= &Souls::getDefLvUltra;
	kSoulLvDefFuncs_Array[kSoulIndex_Negative]	= &Souls::getDefLvNegative;
	
	kSoulVlDefFuncs_Array[kSoulIndex_Subpetty]	= &Souls::getDefVlSubpetty;
	kSoulVlDefFuncs_Array[kSoulIndex_Petty]		= NULL;
	kSoulVlDefFuncs_Array[kSoulIndex_Lesser]	= NULL;
	kSoulVlDefFuncs_Array[kSoulIndex_Common]	= NULL;
	kSoulVlDefFuncs_Array[kSoulIndex_Greater]	= NULL;
	kSoulVlDefFuncs_Array[kSoulIndex_Grand]		= NULL;
	kSoulVlDefFuncs_Array[kSoulIndex_Ultra]		= &Souls::getDefVlUltra;
	kSoulVlDefFuncs_Array[kSoulIndex_Negative]	= &Souls::getDefVlNegative;
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideSubpetty", kSoulVlOvrGMSTs_Array[kSoulIndex_Subpetty]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Subpetty] = new GameSetting("iSoulLevelValueARESOverrideSubpetty", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverridePetty", kSoulVlOvrGMSTs_Array[kSoulIndex_Petty]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Petty] = new GameSetting("iSoulLevelValueARESOverridePetty", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideLesser", kSoulVlOvrGMSTs_Array[kSoulIndex_Lesser]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Lesser] = new GameSetting("iSoulLevelValueARESOverrideLesser", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideCommon", kSoulVlOvrGMSTs_Array[kSoulIndex_Common]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Common] = new GameSetting("iSoulLevelValueARESOverrideCommon", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideGreater", kSoulVlOvrGMSTs_Array[kSoulIndex_Greater]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Greater] = new GameSetting("iSoulLevelValueARESOverrideGreater", (SInt32) -1);

	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideGrand", kSoulVlOvrGMSTs_Array[kSoulIndex_Grand]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Grand] = new GameSetting("iSoulLevelValueARESOverrideGrand", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideUltra", kSoulVlOvrGMSTs_Array[kSoulIndex_Ultra]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Ultra] = new GameSetting("iSoulLevelValueARESOverrideUltra", (SInt32) -1);
	
	if ( !GameSettingCollection::GameSettings.settingMap.GetAt("iSoulLevelValueARESOverrideNegative", kSoulVlOvrGMSTs_Array[kSoulIndex_Negative]) )
		kSoulVlOvrGMSTs_Array[kSoulIndex_Negative] = new GameSetting("iSoulLevelValueARESOverrideNegative", (SInt32) -1);
	
	kSoulVlOvrScpts_Array[kSoulIndex_Subpetty]	= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Petty]		= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Lesser]	= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Common]	= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Greater]	= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Grand]		= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Ultra]		= NULL;
	kSoulVlOvrScpts_Array[kSoulIndex_Negative]	= NULL;
}

Souls::~Souls() {
/*	for ( int i = 0; i < kSoulIndex_MAX; ++i ) {
		if ( kSoulLvOvrGMSTs_Array[i] )
			delete kSoulLvOvrGMSTs_Array[i];
	}*/
}

UInt16 Souls::getLv(UInt8 soul) const {
	UInt16 lv = 0;
	if ( 0 <= soul && soul < kSoulIndex_MAX ) {
		if ( kSoulLvOvrGMSTs_Array[soul] && kSoulLvOvrGMSTs_Array[soul]->value.i >= 0 ) {
			lv = kSoulLvOvrGMSTs_Array[soul]->value.i;
		}

		else if ( kSoulLvOvrScpts_Array[soul] > 0 ) {
			lv = callScptNoArgs(kSoulLvOvrScpts_Array[soul]);
		}

		else if ( kSoulgemIDs_Array[soul] > 0 ) {
			lv = getSoulLvFromLL(soul);
		}

		else if ( kSoulLvDefFuncs_Array[soul] ) {
			lv = (this->*kSoulLvDefFuncs_Array[soul])();
		}
	}
//	_VMESSAGE("Soul %i level %i.", soul, lv);
	return lv;
}

bool Souls::setLv(UInt16 level, UInt8 soul) {
	if ( kSoulLvOvrGMSTs_Array[soul] ) {
		kSoulLvOvrGMSTs_Array[soul]->value.i = level;
		return true;
	}
	else
		return false;
}

bool Souls::unsetLv(UInt8 soul) {
	if ( kSoulLvOvrGMSTs_Array[soul] ) {
		kSoulLvOvrGMSTs_Array[soul]->value.i = -1;
		return true;
	}
	else
		return false;
}

SInt32 Souls::getVl(UInt8 soul) const {
	SInt32 vl = -1;
	if ( 0 <= soul && soul < kSoulIndex_MAX ) {
		if ( kSoulVlOvrGMSTs_Array[soul] && kSoulVlOvrGMSTs_Array[soul]->value.i >= 0 ) {
			vl = kSoulVlOvrGMSTs_Array[soul]->value.i;
		}

		else if ( kSoulVlOvrScpts_Array[soul] > 0 ) {
			vl = callScptNoArgs(kSoulVlOvrScpts_Array[soul]);
		}

		else if ( kSoulVlDefGMSTs_Array[soul] ) {
			vl = kSoulVlDefGMSTs_Array[soul]->value.i;
		}

		else if ( kSoulVlDefFuncs_Array[soul] ) {
			vl = (this->*kSoulVlDefFuncs_Array[soul])();
		}
	}
//	_VMESSAGE("Soul %i value %i.", soul, vl);
	return vl;
}

bool Souls::setVl(SInt32 value, UInt8 soul) {
	if ( kSoulVlOvrGMSTs_Array[soul] ) {
		kSoulVlOvrGMSTs_Array[soul]->value.i = value;
		return true;
	}
	else
		return false;
}

bool Souls::unsetVl(UInt8 soul) {
	if ( kSoulVlOvrGMSTs_Array[soul] ) {
		kSoulVlOvrGMSTs_Array[soul]->value.i = -1;
		return true;
	}
	else
		return false;
}

#define defSoulLvGetFn(lv)		UInt16 Souls::getLv ## lv ## () const		{ return getLv(kSoulIndex_ ## lv ## );			}
#define defSoulLvSetFn(lv)		bool Souls::setLv ## lv ## (UInt16 level)	{ return setLv(level, kSoulIndex_ ## lv ## );	}
#define defSoulLvUnsetFn(lv)	bool Souls::unsetLv ## lv ## ()				{ return unsetLv(kSoulIndex_ ## lv ## );		}

#define defSoulLvFns(lv)	\
	defSoulLvGetFn(lv)	\
	defSoulLvSetFn(lv)	\
	defSoulLvUnsetFn(lv)

#define defSoulVlGetFn(lv)		SInt32 Souls::getVl ## lv ## () const		{ return getVl(kSoulIndex_ ## lv ## );			}
#define defSoulVlSetFn(lv)		bool Souls::setVl ## lv ## (SInt32 value)	{ return setVl(value, kSoulIndex_ ## lv ## );	}
#define defSoulVlUnsetFn(lv)	bool Souls::unsetVl ## lv ## ()				{ return unsetVl(kSoulIndex_ ## lv ## );		}

#define defSoulVlFns(lv)	\
	defSoulVlGetFn(lv)	\
	defSoulVlSetFn(lv)	\
	defSoulVlUnsetFn(lv)

#define defSoulFns(lv) defSoulLvFns(lv) defSoulVlFns(lv)

defSoulFns(Subpetty)
defSoulFns(Petty)
defSoulFns(Lesser)
defSoulFns(Common)
defSoulFns(Greater)
defSoulFns(Grand)
defSoulFns(Ultra)
defSoulFns(Negative)

UInt16 Souls::getDefLvSubpetty() const {
	UInt16 pet = getLvPetty();
	UInt16 les = getLvLesser();

	return max(pet-(les-pet)+1, 1);
}

UInt16 Souls::getDefLvUltra() const {
	UInt16 grt = getLvGreater();
	UInt16 gnd = getLvGrand();

	return gnd+(gnd-grt)+1;
}

UInt16 Souls::getDefLvNegative() const {
	return getDefLvSubpetty();
}

SInt32 Souls::getDefVlSubpetty() const {
	return getVlPetty() / 2;
}

SInt32 Souls::getDefVlUltra() const {
	SInt32 grt = getVlGreater();
	SInt32 gnd = getVlGrand();

	return gnd+(gnd-grt);
}

SInt32 Souls::getDefVlNegative() const {
	return getVlPetty() / 2;
}
